home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_500
/
wiconify
/
wiconify-source.lzh
/
Source
/
wIcon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
20KB
|
698 lines
/*
* WICONIFY A utility that allows you to iconify any Intuition window
* on any screen, and to open WB windows on any screen.
*
* wIcon.c Handles most aspects of icon creation and maintenance
*
* Copyright 1990 by Davide P. Cervone, all rights reserved.
* You may use this code, provided this copyright notice is kept intact.
*/
#define INTUITION_PREFERENCES_H /* don't need 'em */
#include <intuition/intuitionbase.h>
#include "wHandler.h"
struct Window *WindowToActivate; /* Activate this window on SELECTUP */
static WSCREEN *Refresh; /* List of screens to be refreshed */
#define ICONDELAY 2L /* For window to come forward for CHANGEREFRESH */
#define MAXWAIT 10 /* Number of attempts if it hasn't come forward */
#define MOVE_DY 2048L /* Distance to move screen when iconified */
#define WINDOW(layer) ((struct Window *)((layer)->Window))
#define LAYERREFRESHBITS (LAYERSIMPLE | LAYERSMART)
#define ICONSCREEN ((WSCREEN *)theIcon->Window->UserData)
/*
* SetRefresh()
*
* Lock the layers of the window's screen
* Change the window's refresh status
* Get the window's layer
* Change the layer's refresh status
* Unlock the screen's layers
*/
static void SetRefresh(theWindow,WindowBits)
struct Window *theWindow;
ULONG WindowBits;
{
struct Layer *theLayer;
UWORD LayerBits = (WindowBits == SMART_REFRESH)? LAYERSMART: LAYERSIMPLE;
Forbid();
LockLayerInfo(&theWindow->WScreen->LayerInfo);
theWindow->Flags = (theWindow->Flags & ~REFRESHBITS) | WindowBits;
theLayer = theWindow->WLayer;
theLayer->Flags = (theLayer->Flags & ~LAYERREFRESHBITS) | LayerBits;
UnlockLayerInfo(&theWindow->WScreen->LayerInfo);
Permit();
}
/*
* SetBackdrop()
*
* Lock the screen's layers
* Add or remove the BACKDROP flag appropriately
* Get the window's first layer (GZZ and requesters may give it more)
* While there are more layers for this window (we assume they are sequential)
* Set the backdrop status of the layer
* Go on to the next layer
* Start over again with the first layer behind the window
* For any layers nbelowing to this window
* Set the backdrop status of the layer
* Move on to the previous layer
* Unlock the layers
*/
static void SetBackdrop(theWindow,Backdrop)
struct Window *theWindow;
int Backdrop;
{
struct Layer *theLayer;
Forbid();
LockLayerInfo(&theWindow->WScreen->LayerInfo);
if (Backdrop)
theWindow->Flags |= BACKDROP;
else
theWindow->Flags &= ~BACKDROP;
theLayer = theWindow->WLayer;
while (theLayer && theLayer->Window == (APTR)theWindow)
{
if (Backdrop)
theLayer->Flags |= LAYERBACKDROP;
else
theLayer->Flags &= ~LAYERBACKDROP;
theLayer = theLayer->front;
}
theLayer = theWindow->WLayer->back;
while (theLayer && theLayer->Window == (APTR)theWindow)
{
if (Backdrop)
theLayer->Flags |= LAYERBACKDROP;
else
theLayer->Flags &= ~LAYERBACKDROP;
theLayer = theLayer->back;
}
UnlockLayerInfo(&theWindow->WScreen->LayerInfo);
Permit();
}
/*
* TopWindow()
*
* Lock the screen's layers so they don't change while we look
* Start with the top-most layer
* Look through the layer list for the first one with a window pointer
* Get the layer's window pointer
* Unlock the layers
* Return the window.
*/
static struct Window *TopWindow(theScreen)
struct Screen *theScreen;
{
struct Window *theWindow = NULL;
struct Layer_Info *theLayerInfo = &(theScreen->LayerInfo);
struct Layer *theLayer;
LockLayers(theLayerInfo);
theLayer = theLayerInfo->top_layer;
while (theLayer && WINDOW(theLayer) == NULL) theLayer = theLayer->back;
if (theLayer) theWindow = WINDOW(theLayer);
UnlockLayers(theLayerInfo);
return(theWindow);
}
/*
* HideWindow()
*
* If the icon is a screen icon (not a window icon)
* If the screen is the active one, activate the WB Iconify window
* Send the screen to the back
* Move the screen off the bottom of the display
* Link the screen's icon into the WB screen list
* Otherwise
* If the icon is supposed to have its refresh status changed
* If the window is a SMART_REFRESH one
* Bring the window to the front
* Wait for the window to come to the front (timeout after MAXWAIT)
* (we must have the window completely uncovered before we change
* the refresh status, otherwise the refresh regions get completely
* messed up!)
* Set the refresh type to SIMPLE_REFRESH
* Mark the icon as changed
* If the window is not already a backdrop window
* Mark it as a backdrop window
* Record the change so we can undo it later
* If the window is getting refresh messages
* Turn them off (dont update while we can't see it!)
* Record the change
* Finally, send the window to the back (behind the wIconify backdrop)
*/
static void HideWindow(theIcon,Flags)
WICONREF *theIcon;
UWORD Flags;
{
struct Window *theWindow = theIcon->Window;
short i = MAXWAIT;
if (theIcon->Icon.Flags & WI_SCREENICON)
{
Forbid();
if (IntuitionBase->ActiveScreen == ICONSCREEN->Screen)
ActivateWindow(RealWB->BackDrop);
Permit();
ScreenToBack(ICONSCREEN->Screen);
MoveScreen(ICONSCREEN->Screen,0L,MOVE_DY);
LinkIcon(theIcon,RealWB);
} else {
if ((theIcon->Icon.Flags & WI_CHANGEREFRESH) || (Flags & WI_CHANGE))
{
if ((theWindow->Flags & REFRESHBITS) == SMART_REFRESH)
{
WindowToFront(theWindow);
while (theWindow != TopWindow(theIcon->Screen->Screen) && --i)
Delay(ICONDELAY);
SetRefresh(theWindow,SIMPLE_REFRESH);
theIcon->Icon.Flags |= WI_REFRESHCHANGE;
}
}
if ((theWindow->Flags & BACKDROP) == FALSE)
{
SetBackdrop(theWindow,TRUE);
theIcon->Icon.Flags |= WI_BACKDROPCHANGE;
}
if ((theWindow->Flags & NOCAREREFRESH) == FALSE)
{
theWindow->Flags |= NOCAREREFRESH;
theIcon->Icon.Flags |= WI_NOCARECHANGE;
}
WindowToBack(theWindow);
}
}
/*
* ShowWindow()
*
* If the icon is a screen icon
* Move the screen back to its previous location
* Bring it to the front
* Otherwise
* If the window was not a BACKDROP one before, fix its layers
* If we changes the refresh report flag, reset it
* Bring the window to the front
* If we changed the refresh type of the window
* Wait for the window to appear at the front (timeout after MAXWAIT)
* Set the refresh type to SMART_REFRESH
* Remove the flags that say what changes were made
*/
static void ShowWindow(theIcon)
WICONREF *theIcon;
{
struct Window *theWindow = theIcon->Window;
short i = MAXWAIT;
if (theIcon->Icon.Flags & WI_SCREENICON)
{
MoveScreen(ICONSCREEN->Screen,0L,-MOVE_DY);
ScreenToFront(ICONSCREEN->Screen);
} else {
if (theIcon->Icon.Flags & WI_BACKDROPCHANGE)
SetBackdrop(theWindow,FALSE);
if (theIcon->Icon.Flags & WI_NOCARECHANGE)
theWindow->Flags &= ~NOCAREREFRESH;
WindowToFront(theWindow);
if (theIcon->Icon.Flags & WI_REFRESHCHANGE)
{
while (theWindow != TopWindow(theIcon->Screen->Screen) && --i)
Delay(ICONDELAY);
SetRefresh(theWindow,SMART_REFRESH);
}
theIcon->Icon.Flags &= ~WI_CHANGEBITS;
}
}
/*
* RefreshIcons()
*
* If there is a screen to refresh
* If we are supposed to clear the screen, mark it to be cleared
* If the screen is not already in the list
* Link it into the list and mark it as in the list
* (The refreshing is delayed until after all the messages are processed
* so we don't refresh the same screen multiple times)
*/
void RefreshIcons(theScreen,ClearIt)
WSCREEN *theScreen;
int ClearIt;
{
Forbid();
if (theScreen)
{
if (ClearIt) theScreen->Flags |= WI_CLEARIT;
if ((theScreen->Flags & WI_REFRESH) == FALSE)
{
theScreen->Flags |= WI_REFRESH;
theScreen->NextRefresh = Refresh;
Refresh = theScreen;
}
}
Permit();
}
/*
* DrawGadgets()
*
* Get the first gadget on the screen
* While there are more gadgets
* Temporarily use the MutualExclude flag as a backward pointer
* Save the pointer to the last gadget seen
* Go on to the next one
* Start at the end of the list
* While there are more gadgets to draw
* Get the next gadget from MutualExclude (where we stored it above)
* Reset MutualExclude to zero
* Draw the given gadget
* (The gadgets are drawn in reverse order to make them overlap correctly.
* One could replace this routine by RefreshGadgets if desired. There are
* two reason's not to, however; RefreshGadgets draws all the gadgets first
* then goes back and adds any select imagery or complements. This causes
* undue flickering of the icons if there are many of them selected. Also,
* if any selected ones overlap, the complementation cancels out on the
* overlapped region)
*/
static void DrawGadgets(theScreen)
WSCREEN *theScreen;
{
struct Gadget *theGadget = theScreen->BackDrop->FirstGadget;
struct Gadget *IconGadget = NULL;
while (theGadget)
{
theGadget->MutualExclude = (LONG) IconGadget;
IconGadget = theGadget;
theGadget = theGadget->NextGadget;
}
while (IconGadget)
{
theGadget = IconGadget;
IconGadget = (struct Gadget *) theGadget->MutualExclude;
theGadget->MutualExclude = 0L;
RefreshGList(theGadget,theScreen->BackDrop,NULL,ONE);
}
}
/*
* RefreshScreens()
*
* For each screen in the list
* If it still has a backdrop window (ie, the screen is not closing)
* If we are supposed to clear the screen, do so
* If the screen has gadgets, draw them
* Clear the screen's refresh bits
* Move on to the next screen
*/
void RefreshScreens()
{
Forbid();
while (Refresh)
{
if (Refresh->BackDrop)
{
if (Refresh->Flags & WI_CLEARIT) SetRast(Refresh->BackDrop->RPort,0L);
if (Refresh->BackDrop->FirstGadget) DrawGadgets(Refresh);
}
Refresh->Flags &= ~(WI_REFRESH| WI_CLEARIT);
Refresh = Refresh->NextRefresh;
}
Permit();
}
/*
* UnLinkRefresh()
*
* Find the given screen in the refresh list and remove it.
*/
void UnLinkRefresh(theScreen)
WSCREEN *theScreen;
{
WSCREEN **ScreenPtr;
Forbid();
ScreenPtr = &Refresh;
while (*ScreenPtr && *ScreenPtr != theScreen)
ScreenPtr = &((*ScreenPtr)->NextRefresh);
if (*ScreenPtr) *ScreenPtr = theScreen->NextRefresh;
Permit();
}
/*
* RemoveIcon()
*
* If the icon has a gadget
* If the icon is selected
* Unlink the gadget from the selection list
* If this was the last icon on the screen update the menus
* Mark the icon as not selected
* If the screen still has a backdrop window
* Remove the gadget from the window
* Free the icon's gadget structure
* Clear and refresh the screen's icons
*/
void RemoveIcon(theIcon)
WICONREF *theIcon;
{
if (theIcon->Gadget)
{
if (theIcon->Icon.Flags & WI_SELECTED)
{
UnLinkGadget(theIcon->Gadget);
if (theIcon->Screen->Selected == NULL) UpdateActiveMenu();
theIcon->Icon.Flags &= ~WI_SELECTED;
}
if (theIcon->Screen->BackDrop)
RemoveGadget(theIcon->Screen->BackDrop,theIcon->Gadget);
FREESTRUCT(wGadget,theIcon->Gadget); theIcon->Gadget = NULL;
RefreshIcons(theIcon->Screen,TRUE);
}
}
/*
* DeleteIcon()
*
* Unlink the icon from the screen's list
* Remove the icon gadget from the screen
* If the screen has no more icons
* If the screen has a task waiting to close it
* Signal that task that it is now OK to close the screen
* If Iconify is waiting to end, signal that it can try again
* Update the menus (deactivate OPENALL, etc)
* If the icon is not a screen icon (which is part of the scren structure)
* Free the icon's memory
*/
void DeleteIcon(theIcon)
WICONREF *theIcon;
{
UnLinkIcon(theIcon);
RemoveIcon(theIcon);
if (theIcon->Screen->IconRef == NULL)
{
if (theIcon->Screen->CloseTask)
Signal(theIcon->Screen->CloseTask,theIcon->Screen->CloseSignal);
if (EndSignal) Signal(IconTask,EndSignal);
UpdateActiveMenu();
}
if ((theIcon->Icon.Flags & WI_SCREENICON) == FALSE)
FREESTRUCT(wIconRef,theIcon);
}
/*
* CloseIcon()
*
* If the icon is allowed to be closed
* If the icon wants to receive close messages, send one
* Otherwise if the icon's window currently has a requester up, no nothing
* Otherwise send the CLOSEWINDOW message to simulate pressing the
* close gadget of the window
*/
void CloseIcon(theIcon)
WICONREF *theIcon;
{
if ((theIcon->Icon.Flags & WI_NOCLOSE) == FALSE)
{
if (theIcon->Icon.Report & WI_REPORTCLOSE)
ReportEvent(WI_REPORTCLOSE,theIcon);
else if (theIcon->Window && theIcon->Window->FirstRequest) /* nothing */;
else SendIntuiMessage(CLOSEWINDOW,theIcon->Window);
}
}
/*
* Iconify()
*
* If we have an icon
* If the icon is not already iconified, and it is allowed to be, and there
* is somewhere to put the icon
* If the icon is for a window or (if it IS a screen icon) if the
* real WB screen is open and is not the screen whose icon this is
* Find out it the icon's window is the active one
* If so, activate the screen's backdrop window
* Get a new gadget for the icon
* If one was able to be allocated
* Mark the icon as iconified
* If the icon has an associated window
* If it has no close gadget, mark the icon as not closable
* Hide the window behind the wIconify backdrop window
* Set up the gadget for the icon
* Add the gadget to the backdrop window
* Refresh the screen
* If the icon wants iconification reports, send one
* If the icon's window was the active one, activate its icon
*/
void Iconify(theIcon,Flags)
WICONREF *theIcon;
UWORD Flags;
{
int isActive;
if (theIcon)
{
if ((theIcon->Icon.Flags & (WI_ICONIFIED| WI_NOICONIFY)) == FALSE &&
theIcon->Screen->BackDrop)
{
if ((theIcon->Icon.Flags & WI_SCREENICON) == FALSE ||
(RealWB && ICONSCREEN != RealWB))
{
isActive = (theIcon->Window == IntuitionBase->ActiveWindow);
if (isActive) ActivateWindow(theIcon->Screen->BackDrop), Delay(1L);
if (NEWSTRUCT(wGadget,theIcon->Gadget))
{
theIcon->Icon.Flags |= WI_ICONIFIED;
if (theIcon->Window)
{
if ((theIcon->Window->IDCMPFlags & CLOSEWINDOW) == FALSE)
theIcon->Icon.Flags |= WI_NOCLOSE;
HideWindow(theIcon,Flags);
}
SetupGadget(theIcon);
AddGadget(theIcon->Screen->BackDrop,theIcon->Gadget,0);
RefreshIcons(theIcon->Screen,TRUE);
Forbid();
if (theIcon->Icon.Report & WI_REPORTICONIFIED)
ReportEvent(WI_REPORTICONIFIED,theIcon);
if (isActive) SelectIcon(theIcon,FALSE);
Permit();
}
}
}
}
}
/*
* Restore()
*
* If we have an icon to restore
* If it is iconified
* If the icon wants restores reported, report it
* Otherwise
* If the icon has a window
* Bring it out from behind the backdrop window
* If we are to activate the window right away, do so
* Otherwise record it for later activation
* If we are not saving the icon's position, clear its position
* Otherwise save the icon's position
* If we are reporting restoration events, do so
* If the icon is a screen icon
* Remove the icon from the WB screen and reset its screen pointer
* Otherwise if the icon has a window remove the icon from the screen
* (don't remove icons with no windows - they must call DeleteIcon)
*/
void Restore(theIcon,ActivateNow)
WICONREF *theIcon;
int ActivateNow;
{
if (theIcon)
{
if (theIcon->Icon.Flags & WI_ICONIFIED)
{
if (theIcon->Icon.Report & WI_REPORTOPEN)
{
ReportEvent(WI_REPORTOPEN,theIcon);
} else {
if (theIcon->Window)
{
ShowWindow(theIcon);
if (ActivateNow) ActivateWindow(theIcon->Window);
else WindowToActivate = theIcon->Window;
theIcon->Icon.Flags &= ~WI_ICONIFIED;
}
if (theIcon->Icon.Flags & WI_NOSAVEPOS)
{
theIcon->Icon.x = theIcon->Icon.y = 0;
} else {
theIcon->Icon.x = theIcon->Gadget->Gadget.LeftEdge;
theIcon->Icon.y = theIcon->Gadget->Gadget.TopEdge;
}
if (theIcon->Icon.Report & WI_REPORTRESTORE)
ReportEvent(WI_REPORTRESTORE,theIcon);
if (theIcon->Icon.Flags & WI_SCREENICON)
{
DeleteIcon(theIcon);
theIcon->Screen = ICONSCREEN;
} else if (theIcon->Window) RemoveIcon(theIcon);
}
}
}
}
/*
* OpenAllIcons()
*
* If a screen was specified
* Get the first icon on the screen
* While there are more icons to handle
* Restore the icon and go on
* (we save the pointer to the next icon first since Restore may
* free the icon's memory and invalidate the pointer)
*/
void OpenAllIcons(theScreen)
WSCREEN *theScreen;
{
WICONREF *theIcon,*nextIcon;
if (theScreen)
{
theIcon = theScreen->IconRef;
while (theIcon)
{
nextIcon = theIcon->Next;
Restore(theIcon,TRUE);
theIcon = nextIcon;
}
}
}
/*
* OpenSelected()
*
* If there is a screen to work with
* Get the first gadget selected on the screen
* While there are more gadgets to handle
* Restore the window associated with gadget
* Go on to the next one
* (we save the pointer to the next gadget before restoring since
* Restore() will remove the gadget before it returns)
*/
void OpenSelected(theScreen,Activate)
WSCREEN *theScreen;
int Activate;
{
struct wGadget *theGadget,*nextGadget;
if (theScreen)
{
theGadget = theScreen->Selected;
while (theGadget)
{
nextGadget = theGadget->NextSelect;
Restore(theGadget->Gadget.UserData,Activate);
theGadget = nextGadget;
}
}
}
/*
* CloseSelected()
*
* Start with the first selected gadget on the screen
* While there are more gadgets to handle
* Close the icon associated with the gadget
* Go on to the next gadget
*/
void CloseSelected(theScreen)
WSCREEN *theScreen;
{
struct wGadget *theGadget = theScreen->Selected;
struct wGadget *nextGadget;
Forbid();
while (theGadget)
{
nextGadget = theGadget->NextSelect;
CloseIcon(GADGETICON);
theGadget = nextGadget;
}
Permit();
}
/*
* LockSelected()
*
* Start with the first selected gadget on the screen
* Look through the list to see if any are locked
* (if they are all locked, LockIt will remain FALSE, else it will be TRUE)
* For each selected gadget on the screen
* Set the LOCKED flag appropriately
*/
void LockSelected(theScreen)
WSCREEN *theScreen;
{
struct wGadget *theGadget = theScreen->Selected;
int LockIt = FALSE;
Forbid();
while (theGadget && !LockIt)
{
LockIt = ((GADGETICON->Icon.Flags & WI_LOCKED) == FALSE);
theGadget=theGadget->NextSelect;
}
for (theGadget = theScreen->Selected; theGadget;
theGadget = theGadget->NextSelect)
{
if (LockIt)
GADGETICON->Icon.Flags |= WI_LOCKED;
else
GADGETICON->Icon.Flags &= ~WI_LOCKED;
}
Permit();
}